import json
from django.utils import timezone
from django.shortcuts import render
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django_redis import get_redis_connection
from decimal import Decimal
from django import http
from django.db import transaction

from goods.models import SKU
from users.models import Addresses
from utils.views import LoginRequiredJSONMixin
from .models import OrderInfo, OrderGoods
from utils.response_code import RETCODE


# Create your views here.
class OrderSuccessView(LoginRequiredMixin, View):
    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }

        return render(request, 'order_success.html', context)


class OrderSettlementView(LoginRequiredMixin, View):
    def get(self, request):
        user = request.user

        try:
            addresses = Addresses.objects.filter(user=user, is_deleted=False)
        except Addresses.DoesNotExist:
            addresses = None

        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        redis_cart_selected = redis_conn.smembers('selected_%s' % user.id)

        new_sku_id_dict = {}
        for sku_id in  redis_cart_selected:
            new_sku_id_dict[int(sku_id)] = int(redis_cart[sku_id])

        sku_ids = new_sku_id_dict.keys()

        total_count = 0
        total_amount = Decimal(0.00)
        freight = Decimal(10.00)

        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            sku.count = new_sku_id_dict[sku.id]
            sku.amount = sku.price * sku.count

            total_count += sku.count
            total_amount += sku.amount

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'total_payment': total_amount + freight
        }

        return render(request, 'place_order.html', context)


class OrderCommitView(LoginRequiredJSONMixin, View):
    def post(self, request):
        json_str = request.body.decode()
        json_dict = json.loads(json_str)
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('Missing required parameters')

        try:
            address = Addresses.objects.get(id=address_id)
        except Addresses.DoesNotExist:
            return http.HttpResponseForbidden('Error address id')

        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('Error pay method')

        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                user = request.user
                order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal(0.00),
                    freight=Decimal(10.00),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                redis_cart_selected = redis_conn.smembers('selected_%s' % user.id)

                new_sku_id_dict = {}
                for sku_id in redis_cart_selected:
                    new_sku_id_dict[int(sku_id)] = int(redis_cart[sku_id])

                sku_ids = new_sku_id_dict.keys()

                for sku_id in sku_ids:
                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        sku_count = new_sku_id_dict[sku.id]

                        if sku_count > sku.stock:
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': 'Not enough stock'})

                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count

                        # import time
                        # time.sleep(7)

                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)

                        if result == 0:
                            continue


                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # try:
                        #     sku.save()
                        # except Exception as e:
                        #     return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': 'Error, Retry please'})

                        sku.spu.sales += sku_count
                        sku.spu.save()

                        order.total_count += sku_count
                        order.total_amount += sku_count * sku.price

                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price
                        )

                        break

                order.total_amount += order.freight
                order.save()
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': 'Order failure'})

        transaction.savepoint_commit(save_id)
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'order_id': order_id})
